﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

namespace YioksPlanEditor.Tools
{
    public class XmlUtil
    {
        private static ArrayList _variable3 = new ArrayList();

        /// <summary>
        /// 遍历对象
        /// </summary>
        /// <param name="obj">对象</param>
        public static string GetObjXml(object obj)
        {
            _variable3 = _SetVariable3();
            if (obj == null)
                return "<Null>空对象</Null>";
            string xmlInfo = _GetObjXml(obj);
            return "<xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\">" + xmlInfo + "</xml>";
        }

        private static string _GetObjXml(object obj)
        {
            bool isTypeInfo;
            string info = _ObjTypeInfo(obj, "", new List<object>(), out isTypeInfo);
            if (isTypeInfo)
                return "<MainObject>" + info + "</MainObject>";
            else
                if (obj.GetType().ToString().Contains("System.Runtime"))
                return "<" + ((Type)obj).Name + ">" + _ObjForeach(obj, "", new List<object>()) + "</" + ((Type)obj).Name + ">";
            else
                return "<" + obj.GetType().Name + ">" + _ObjForeach(obj, "", new List<object>()) + "</" + obj.GetType().Name + ">";
        }

        private static string _ObjForeach(object obj, string info, List<object> listObj)
        {
            bool isTypeInfo;
            info = _ObjTypeInfo(obj, info, listObj, out isTypeInfo);
            if (isTypeInfo)
                return info;

            Type t;
            if (obj.GetType().ToString().Contains("System.Runtime"))
                t = (Type)obj;
            else
                t = obj.GetType();
            try
            {
                foreach (var member in t.GetMembers())
                {
                    if (member.MemberType == MemberTypes.Field)
                    {
                        FieldInfo fieldInfo = ((FieldInfo)member);
                        try
                        {
                            if (_IsVariable3(fieldInfo.GetValue(obj)))
                                info = info + "<" + member.Name + ">" + _StrToXml(fieldInfo.GetValue(obj).ToString()) + "</" + member.Name + ">\r\n";
                            else
                            {
                                if (fieldInfo.GetValue(obj).GetType().IsGenericType)
                                {
                                    info = info + "<" + member.Name + " >\r\n";
                                    info = _ObjGenericType(fieldInfo.GetValue(obj), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (fieldInfo.GetValue(obj).GetType().IsArray)
                                {
                                    info = info + "<" + member.Name + " >\r\n";
                                    info = _ObjGenericType(fieldInfo.GetValue(obj), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (fieldInfo.GetValue(obj).GetType().IsEnum)
                                    info = info + "<" + member.Name + ">" + _StrToXml(fieldInfo.GetValue(null).ToString()) + "</" + member.Name + ">\r\n";
                                else if (fieldInfo.GetValue(obj).GetType() == new Hashtable().GetType())
                                {
                                    info = info + "<" + member.Name + " >\r\n";
                                    info = _ObjHashtable(fieldInfo.GetValue(obj), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (fieldInfo.GetValue(obj).GetType() == new ArrayList().GetType())
                                {
                                    info = info + "<" + member.Name + " >\r\n";
                                    info = _ObjGenericType(fieldInfo.GetValue(obj), info, listObj);
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else
                                {
                                    info = info + "<" + member.Name + " >\r\n";
                                    info = _ObjForeach(fieldInfo.GetValue(obj), info, listObj);
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                            }
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                    else if (member.MemberType == MemberTypes.Property)
                    {
                        try
                        {
                            if (t.GetProperty(member.Name) == null) continue;
                            var mInfo = t.GetProperty(member.Name).GetGetMethod();
                            if (!_IsVariable3(mInfo.Invoke(obj, null)))
                            {
                                if (mInfo.Invoke(obj, null).GetType().IsGenericType)
                                {
                                    info = info + "<" + member.Name + ">\r\n";
                                    info = _ObjGenericType(mInfo.Invoke(obj, null), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (mInfo.Invoke(obj, null).GetType().IsArray)
                                {
                                    info = info + "<" + member.Name + ">\r\n";
                                    info = _ObjGenericType(mInfo.Invoke(obj, null), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (mInfo.Invoke(obj, null).GetType().IsEnum)
                                    info = info + "<" + member.Name + ">" + _StrToXml(mInfo.Invoke(obj, null).ToString()) + "</" + member.Name + ">\r\n";
                                else if (mInfo.Invoke(obj, null).GetType() == new Hashtable().GetType())
                                {
                                    info = info + "<" + member.Name + ">\r\n";
                                    info = _ObjHashtable(mInfo.Invoke(obj, null), info, listObj) + "\r\n";
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else if (mInfo.Invoke(obj, null).GetType() == new ArrayList().GetType())
                                {
                                    info = info + "<" + member.Name + ">\r\n";
                                    info = _ObjGenericType(mInfo.Invoke(obj, null), info, listObj);
                                    info = info + "</" + member.Name + ">\r\n";
                                }
                                else
                                {
                                    info = info + "<" + member.Name + ">\r\n";
                                    info = _ObjForeach(mInfo.Invoke(obj, null), info, listObj);
                                    info = info + "</" + member.Name + ">\r\n";
                                }

                            }
                            else
                                info = info + "<" + member.Name + ">" + _StrToXml(mInfo.Invoke(obj, null).ToString()) + "</" + member.Name + ">\r\n";
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                }
            }
            catch
            {
                // ignored
            }
            return info;
        }

        private static string _ObjTypeInfo(object obj, string info, List<object> listObj, out bool isTypeInfo)
        {
            isTypeInfo = false;
            if (obj.GetType().ToString().Contains("KeyValuePair"))
                return info;
            try
            {
                if (_IsVariable3(obj))
                {
                    isTypeInfo = true;
                    info = info + "<object>" + _StrToXml(obj.ToString()) + "</object>\r\n";
                }
                else
                {
                    if (obj.GetType().IsGenericType)
                    {
                        isTypeInfo = true;
                        info = info + "<object>\r\n";
                        info = _ObjGenericType(obj, info, listObj) + "\r\n";
                        info = info + "</object>\r\n";
                    }
                    else if (obj.GetType().IsArray)
                    {
                        isTypeInfo = true;
                        info = info + "<object>\r\n";
                        info = _ObjGenericType(obj, info, listObj) + "\r\n";
                        info = info + "</object>\r\n";
                    }
                    else if (obj.GetType().IsEnum)
                    {
                        isTypeInfo = true;
                        info = info + "<object>" + _StrToXml(obj.ToString()) + "</object>\r\n";
                    }
                    else if (obj.GetType() == new Hashtable().GetType())
                    {
                        isTypeInfo = true;
                        info = info + "<object>\r\n";
                        info = _ObjHashtable(obj, info, listObj) + "\r\n";
                        info = info + "</object>\r\n";
                    }
                    else if (obj.GetType() == new ArrayList().GetType())
                    {
                        isTypeInfo = true;
                        info = info + "<object>\r\n";
                        info = _ObjGenericType(obj, info, listObj);
                        info = info + "</object>\r\n";
                    }
                }
            }
            catch
            {
                // ignored
            }
            if (_ListObjContains(obj, listObj))
            {
                isTypeInfo = true;
                return info;
            }
            return info;
        }

        private static string _ObjGenericType(object obj, string info, List<object> listObj)
        {
            if (_ListObjContains(obj, listObj))
                return info;

            try
            {
                foreach (object skey in (IEnumerable)obj)
                {
                    if (_IsVariable3(skey))
                    {
                        info = info + "<item>\r\n";
                        info = info + "<" + skey.GetType().Name + ">" + _StrToXml(skey.ToString()) + "</" + skey.GetType().Name + ">\r\n";
                        info = info + "</item>\r\n";
                    }
                    else
                    {
                        info = info + "<item>\r\n";
                        info = _ObjForeach(skey, info, listObj) + "\r\n";
                        info = info + "</item>\r\n";
                    }
                }
            }
            catch
            {
                // ignored
            }
            return info;
        }

        private static string _ObjHashtable(object obj, string info, List<object> listObj)
        {
            if (_ListObjContains(obj, listObj))
                return info;
            Hashtable htObj = (Hashtable)obj;
            foreach (object skey in htObj.Keys)
            {
                info = info + "<item>\r\n";
                try
                {
                    info = info + "<key type=\"" + skey.GetType().Name + "\">";
                    if (_IsVariable3(skey))
                        info = info + _StrToXml(skey.ToString());
                    else
                        info = _ObjForeach(skey, info, listObj) + "\r\n";
                    info = info + "</key>\r\n";
                }
                catch
                {
                    // ignored
                }

                try
                {
                    object skeyObj = htObj[skey];
                    info = info + "<values type=\"" + skeyObj.GetType().Name + "\">";
                    if (_IsVariable3(skeyObj))
                        info = info + _StrToXml(skeyObj.ToString());
                    else
                        info = _ObjForeach(skeyObj, info, listObj) + "\r\n";
                    info = info + "</values>\r\n";
                }
                catch
                {
                    // ignored
                }

                info = info + "</item>\r\n";
            }
            return info;
        }

        private static string _ObjEnum(object obj, string info, List<object> listObj)
        {
            if (_ListObjContains(obj, listObj))
                return info;
            string[] objNames = Enum.GetNames(obj.GetType());
            return _ObjGenericType(objNames, info, listObj);
        }

        private static bool _ListObjContains(object obj, List<object> listObj)
        {
            //if (_Obj.GetType().Name.Contains("Color"))
            //    return true;
            //if (_Obj.GetType().Name.Contains("FontFamily"))
            //    return true;

            //if (_ListObj.Contains(_Obj))
            //    return true;

            //_ListObj.Add(_Obj);
            return false;
        }

        private static bool _IsVariable3(object _object)
        {
            foreach (object t in _variable3)
            {
                if (_object.GetType().Equals(t))
                    return true;
            }
            return false;
        }

        private static string _StrToXml(string str)
        {
            str = str.Replace("&", "&amp;");
            str = str.Replace("<", "&lt;");
            str = str.Replace(">", "&gt;");
            str = str.Replace("'", "&apos;");
            str = str.Replace("\"", "&quot;");
            return str;
        }

        private static ArrayList _SetVariable3()
        {
            ArrayList arrType = new ArrayList();
            int a = 1;
            arrType.Add(a.GetType());
            arrType.Add(Convert.ToByte(a).GetType());
            arrType.Add(Convert.ToString(a).GetType());
            arrType.Add(Convert.ToBoolean(a).GetType());
            arrType.Add(Convert.ToDateTime("2009-06-01").GetType());
            arrType.Add(Convert.ToChar(a).GetType());
            arrType.Add(Convert.ToDecimal(a).GetType());
            arrType.Add(Convert.ToDouble(a).GetType());
            arrType.Add(Convert.ToInt16(a).GetType());
            arrType.Add(Convert.ToInt32(a).GetType());
            arrType.Add(Convert.ToInt64(a).GetType());
            arrType.Add(Convert.ToSByte(a).GetType());
            arrType.Add(Convert.ToSingle(a).GetType());
            arrType.Add(Convert.ToUInt16(a).GetType());
            arrType.Add(Convert.ToUInt32(a).GetType());
            arrType.Add(Convert.ToUInt64(a).GetType());
            return arrType;
        }
    }
}
